﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using StockAnalyzer.Core;
using StockAnalyzer.Store;

namespace StockAnalyzer.Analyzer
{
    internal class MovingAverageAlertor
    {
        private readonly StockCollection stocks;
        private readonly UInt16 period;

        public MovingAverageAlertor(StockCollection stocks, UInt16 period)
        {
            this.stocks = stocks;
            this.period = period;
        }

        public void Build()
        {
            var list = new List<StockWithMALine>();
            foreach (Stock s in stocks)
            {
                if ((s.History.Count >= period + 10) && (period > 0))
                {
                    var line = new StockWithMALine(s);
                    line.Make(period);

                    //成交量太小的话，没什么意义
                    if (line.AverageLine[0].AverageVolume >= Utility.VolumeFilter)
                    {
                        list.Add(line);
                    }
                }
            }
            list.Sort(new StockMAComparer());
            save(list);
        }

        private static void save(List<StockWithMALine> list)
        {
            var fs = new FileStream(Utility.TargetPath + "\\moving_average.txt", FileMode.Create);
            var w = new StreamWriter(fs);
            var sl = new FileStream(Utility.TargetPath + "\\stock_list.txt", FileMode.Create);
            var wsl = new StreamWriter(sl);
            try
            {
                foreach (StockWithMALine s in list)
                {
                    w.WriteLine(s.stock.Symbol.ToUpper());
                    for (int i = 0; i < s.AverageLine.Count; i++)
                    {
                        var vi = s.AverageLine[i];
                        string priceAscRateThanYesterday =
                            (vi.PriceAscRateThanYesterday > 0 ? "+" : "") + vi.PriceAscRateThanYesterday.ToString("P02");
                        string priceAscRateThanAverage =
                            (vi.PriceAscRateThanAverage > 0 ? "+" : "") + vi.PriceAscRateThanAverage.ToString("P02");
                        string volumeAceRateThanAverage =
                            (vi.VolumeAscRateThanAverage > 0 ? "+" : "") + vi.VolumeAscRateThanAverage.ToString("P02");
                        string volumeAscRateThanYesterday =
                            (vi.VolumeAscThanYesterday > 0 ? "+" : "") + vi.VolumeAscThanYesterday.ToString("P02");
                        w.WriteLine(vi.Date.Date.ToString("yyyy-MM-dd")
                                    + "  收盘价="
                                    + vi.Price
                                    + " (比昨日 "
                                    + priceAscRateThanYesterday
                                    + ", 比50日均价 "
                                    + priceAscRateThanAverage
                                    + ")"
                                    + "  成交量="
                                    + vi.Volume
                                    + " (比昨日 "
                                    + volumeAscRateThanYesterday
                                    + ", 比50日均量 "
                                    + volumeAceRateThanAverage
                                    + ")");
                    }
                    w.WriteLine("");
                    wsl.WriteLine(s.stock.Symbol);
                }
                w.Flush();
                wsl.Flush();
            }
            finally
            {
                sl.Close();
                fs.Close();
            }
        }
    }

    internal class VolumeInfo
    {
        public readonly DateTime Date;
        public readonly Int64 Volume;
        public readonly double Price;
        public readonly double YesterdayPrice;
        public readonly Int64 YesterdayVolume;
        public readonly Int64 AverageVolume;
        public readonly double AveragePrice;

        public double VolumeAscRateThanAverage
        {
            get
            {
                return ((double)Volume - (double)AverageVolume) / (double)AverageVolume;
            }
        }

        public double PriceAscRateThanAverage
        {
            get
            {
                return (Price - AveragePrice)/AveragePrice;
            }
        }

        public double PriceAscRateThanYesterday
        {
            get
            {
                return (Price - YesterdayPrice)/YesterdayPrice;
            }
        }

        public double VolumeAscThanYesterday
        {
            get
            {
                return ((double)Volume - (double)YesterdayVolume) / (double)YesterdayVolume;
            }
        }

        public VolumeInfo(DateTime date, Int64 volume, double price, double preprice, Int64 prevolume, Int64 avvolume, double avprice)
        {
            Date = date;
            Volume = volume;
            Price = price;
            AverageVolume = avvolume;
            AveragePrice = avprice;
            YesterdayPrice = preprice;
            YesterdayVolume = prevolume;
        }
    }

    internal class StockWithMALine : StockExtend
    {
        public byte Priority=10; //优先级别，0为最高级
        public List<VolumeInfo> AverageLine = new List<VolumeInfo>();
        public StockWithMALine(Stock stock)
            : base(stock)
        {
        }

        internal void Make(Int32 period)
        {
            for (int d = 0; d < 10; d++)
            {
                Int64 volumeSummury = 0;
                double priceSummury = 0;
                for (int i = d; i < d + 50; i++)
                {
                    volumeSummury += stock.History[i].Volume;
                    priceSummury += stock.History[i].Close;
                }

                var vi = new VolumeInfo(stock.History[d].Date,
                                        stock.History[d].Volume,
                                        stock.History[d].Close,
                                        stock.History[d+1].Close,
                                        stock.History[d+1].Volume,
                                        volumeSummury / period,
                                        priceSummury / period
                    );
                AverageLine.Add(vi);
            }
            
            if (AverageLine.Count < 2)
            {
                return;
            }

            double pdf = AverageLine[0].Price - AverageLine[0].AveragePrice;
            double pricePercent = pdf/AverageLine[0].AveragePrice;  //当前价格与五十日线之比

            var volume = AverageLine[0];
            if ((volume.VolumeAscRateThanAverage > 1)
                &&(volume.PriceAscRateThanYesterday > 0.05)
                &&(Math.Abs(volume.PriceAscRateThanAverage) < 0.05))
            {
                Priority = 0;
            }
            else if ((volume.VolumeAscRateThanAverage > 0.5)
                && (volume.PriceAscRateThanYesterday > 0.03)
                && (Math.Abs(volume.PriceAscRateThanAverage) < 0.1))
            {
                Priority = 1;
            }
            else if ((volume.VolumeAscRateThanAverage > 0.3)
                && (volume.PriceAscRateThanYesterday > 0.02)
                && (Math.Abs(volume.PriceAscRateThanAverage) < 0.2))
            {
                Priority = 2;
            }
            else if ((volume.VolumeAscRateThanAverage > 0.1)
                && (volume.PriceAscRateThanYesterday > 0.01)
                && (Math.Abs(volume.PriceAscRateThanAverage) < 0.3))
            {
                Priority = 3;
            }
            if ((volume.PriceAscRateThanYesterday > 0.05)
                && (Math.Abs(volume.PriceAscRateThanAverage) < 0.05))
            {
                Priority = 4;
            }
            else if ((volume.PriceAscRateThanYesterday > 0.03)
                && (Math.Abs(volume.PriceAscRateThanAverage) < 0.1))
            {
                Priority = 5;
            }
            else if ((volume.PriceAscRateThanYesterday > 0.02)
                && (Math.Abs(volume.PriceAscRateThanAverage) < 0.2))
            {
                Priority = 6;
            }
            else if ((volume.PriceAscRateThanYesterday > 0.01)
                && (Math.Abs(volume.PriceAscRateThanAverage) < 0.3))
            {
                Priority = 7;
            }
            else if ((volume.PriceAscRateThanYesterday > 0.05))
            {
                Priority = 8;
            }
            else if ((volume.PriceAscRateThanYesterday > 0.03))
            {
                Priority = 9;
            }
            else if ((volume.PriceAscRateThanYesterday > 0.01))
            {
                Priority = 10;
            }
        }
    }

    class StockMAComparer : IComparer<StockWithMALine>
    {
        #region IComparer<StockWithMALine> Members

        public int Compare(StockWithMALine x, StockWithMALine y)
        {
            if (x.Priority != y.Priority)
            {
                return x.Priority.CompareTo(y.Priority);
            }
            else
            {
                return y.AverageLine[0].VolumeAscRateThanAverage.CompareTo(
                    x.AverageLine[0].VolumeAscRateThanAverage);
            }
        }

        #endregion
    }
}